home *** CD-ROM | disk | FTP | other *** search
/ NeXTSTEP 3.3 (Developer)…68k, x86, SPARC, PA-RISC] / NeXTSTEP 3.3 Dev Intel.iso / NextDeveloper / Source / GNU / cctools / as / app.c next >
C/C++ Source or Header  |  1994-05-10  |  10KB  |  502 lines

  1. /* This is the Assembler Pre-Processor
  2.    Copyright (C) 1987 Free Software Foundation, Inc.
  3.  
  4. This file is part of GAS, the GNU Assembler.
  5.  
  6. GAS is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 1, or (at your option)
  9. any later version.
  10.  
  11. GAS is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with GAS; see the file COPYING.  If not, write to
  18. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  19.  
  20. /* App, the assembler pre-processor.  This pre-processor strips out excess
  21.    spaces, turns single-quoted characters into a decimal constant, and turns
  22.    # <number> <filename> <garbage> into a .line <number>;.file <filename> pair.
  23.    This needs better error-handling.
  24.  */
  25. #include <stdio.h>
  26. #include <string.h>
  27. #include "as.h"
  28. #include "md.h"
  29. #include "app.h"
  30. #include "messages.h"
  31.  
  32. FILE *scrub_file = NULL;
  33. char *scrub_string = NULL;
  34. char *scrub_last_string = NULL;
  35.  
  36. #ifdef NeXT    /* .include feature */
  37. /* These are moved out of do_scrub() so save_scrub_context() can save them */
  38. static state;
  39. static old_state;
  40. static char *out_string;
  41. static char out_buf[20];
  42. static add_newlines = 0;
  43. #endif /* NeXT .include feature */
  44.  
  45. static char    lex [256];
  46. static char    symbol_chars[] = 
  47.     "$._ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
  48.  
  49. #define LEX_IS_SYMBOL_COMPONENT        (1)
  50. #define LEX_IS_WHITESPACE        (2)
  51. #define LEX_IS_LINE_SEPERATOR        (4)
  52. #define LEX_IS_COMMENT_START        (8)    /* JF added these two */
  53. #define LEX_IS_LINE_COMMENT_START    (16)
  54. #define IS_SYMBOL_COMPONENT(c)        (lex [c] & LEX_IS_SYMBOL_COMPONENT)
  55. #define IS_WHITESPACE(c)        (lex [c] & LEX_IS_WHITESPACE)
  56. #define IS_LINE_SEPERATOR(c)        (lex [c] & LEX_IS_LINE_SEPERATOR)
  57. #define IS_COMMENT(c)            (lex [c] & LEX_IS_COMMENT_START)
  58. #define IS_LINE_COMMENT(c)        (lex [c] & LEX_IS_LINE_COMMENT_START)
  59.  
  60. void
  61. do_scrub_begin(
  62. void)
  63. {
  64.     char *p;
  65.     const char *q;
  66.  
  67.     memset(lex, '\0', sizeof(lex));        /* Trust NOBODY! */
  68.     lex [' ']        |= LEX_IS_WHITESPACE;
  69.     lex ['\t']        |= LEX_IS_WHITESPACE;
  70.     for (p =symbol_chars;*p;++p)
  71.         lex [(int)*p] |= LEX_IS_SYMBOL_COMPONENT;
  72.     lex ['\n']        |= LEX_IS_LINE_SEPERATOR;
  73. #ifndef DONTDEF
  74. #ifdef NeXT
  75.     /*
  76.      * This DOES not cause ':' to be a LINE SEPERATOR but does make the
  77.      * second if logic after flushchar: in do_scrub_next_char() to handle
  78.      * "foo :" and strip the blanks.  This is the way has always been and
  79.      * must be this way to work.
  80.      */
  81. #endif /* NeXT */
  82.     lex [':']        |= LEX_IS_LINE_SEPERATOR;
  83. #endif /* !defined(DONTDEF) */
  84.  
  85. #if defined(M88K) || defined(M98K) || defined(HPPA)
  86.     lex ['@']        |= LEX_IS_LINE_SEPERATOR;
  87. #else
  88.     lex [';']        |= LEX_IS_LINE_SEPERATOR;
  89. #endif
  90.     for (q=md_comment_chars;*q;q++)
  91.         lex[(int)*q] |= LEX_IS_COMMENT_START;
  92.     for (q=md_line_comment_chars;*q;q++)
  93.         lex[(int)*q] |= LEX_IS_LINE_COMMENT_START;
  94. }
  95.  
  96. int
  97. scrub_from_file(
  98. void)
  99. {
  100.     return getc(scrub_file);
  101. }
  102.  
  103. void
  104. scrub_to_file(
  105. int ch)
  106. {
  107.     ungetc(ch, scrub_file);
  108. }
  109.  
  110. int
  111. scrub_from_string(
  112. void)
  113. {
  114.     return scrub_string == scrub_last_string ? EOF : *scrub_string++;
  115. }
  116.  
  117. void
  118. scrub_to_string(
  119. int ch)
  120. {
  121.     *--scrub_string = ch;
  122. }
  123.  
  124. int
  125. do_scrub_next_char(
  126. int (*get)(void),
  127. void (*unget)(int ch))
  128. /* FILE *fp; */
  129. {
  130.     /* State 0: beginning of normal line
  131.         1: After first whitespace on normal line (flush more white)
  132.         2: After first non-white on normal line (keep 1white)
  133.         3: after second white on normal line (flush white)
  134.         4: after putting out a .line, put out digits
  135.         5: parsing a string, then go to old-state
  136.         6: putting out \ escape in a "d string.
  137.         7: After putting out a .file, put out string.
  138.         8: After putting out a .file string, flush until newline.
  139.         -1: output string in out_string and go to the state in old_state
  140.         -2: flush text until a '*' '/' is seen, then go to state old_state
  141.     */
  142.  
  143. #ifndef NeXT    /* .include feature */
  144.     static state;
  145.     static old_state;
  146.     static char *out_string;
  147.     static char out_buf[20];
  148.     static add_newlines = 0;
  149. #endif /* NeXT .include feature */
  150.     int ch;
  151.  
  152.     if(state==-1) {
  153.         ch= *out_string++;
  154.         if(*out_string==0) {
  155.             state=old_state;
  156.             old_state=3;
  157.         }
  158.         return ch;
  159.     }
  160.     if(state==-2) {
  161.         for(;;) {
  162.             do ch=(*get)();
  163.             while(ch!=EOF && ch!='\n' && ch!='*');
  164.             if(ch=='\n' || ch==EOF)
  165.                 return ch;
  166.              ch=(*get)();
  167.              if(ch==EOF || ch=='/')
  168.                  break;
  169.             (*unget)(ch);
  170.         }
  171.         state=old_state;
  172.         return ' ';
  173.     }
  174.     if(state==4) {
  175.         ch=(*get)();
  176.         if(ch==EOF || (ch>='0' && ch<='9'))
  177.             return ch;
  178.         else {
  179.             while(ch!=EOF && IS_WHITESPACE(ch))
  180.                 ch=(*get)();
  181.             if(ch=='"') {
  182.                 (*unget)(ch);
  183. #if defined(M88K) || defined(M98K) || defined(HPPA)
  184.                 out_string="@ .file ";
  185. #else
  186.                 out_string="; .file ";
  187. #endif
  188.                 old_state=7;
  189.                 state= -1;
  190.                 return *out_string++;
  191.             } else {
  192.                 while(ch!=EOF && ch!='\n')
  193.                     ch=(*get)();
  194. #ifdef NeXT
  195.                 /* bug fix for bug #8918, which was when
  196.                  * a full line comment line this:
  197.                  * # 40 MP1 = M + 1
  198.                  * got confused with a cpp output like:
  199.                  * # 1 "hello.c" 1
  200.                  */
  201.                 state = 0;
  202. #endif /* NeXT */
  203.                 return ch;
  204.             }
  205.         }
  206.     }
  207.     if(state==5) {
  208.         ch=(*get)();
  209.         if(ch=='"') {
  210.             state=old_state;
  211.             return '"';
  212.         } else if(ch=='\\') {
  213.             state=6;
  214.             return ch;
  215.         } else if(ch==EOF) {
  216.             as_warn("End of file in string: inserted '\"'");
  217.              state=old_state;
  218.             (*unget)('\n');
  219.             return '"';
  220.         } else {
  221.             return ch;
  222.         }
  223.     }
  224.     if(state==6) {
  225.         state=5;
  226.         ch=(*get)();
  227.         switch(ch) {
  228.             /* This is neet.  Turn "string
  229.                more string" into "string\n  more string"
  230.              */
  231.         case '\n':
  232.             (*unget)('n');
  233.             add_newlines++;
  234.             return '\\';
  235.  
  236.         case '"':
  237.         case '\\':
  238.         case 'b':
  239.         case 'f':
  240.         case 'n':
  241.         case 'r':
  242.         case 't':
  243.         case '0':
  244.         case '1':
  245.         case '2':
  246.         case '3':
  247.         case '4':
  248.         case '5':
  249.         case '6':
  250.         case '7':
  251.             break;
  252.         default:
  253.             as_warn("Unknown escape '\\%c' in string: Ignored",ch);
  254.             break;
  255.  
  256.         case EOF:
  257.             as_warn("End of file in string: '\"' inserted");
  258.             return '"';
  259.         }
  260.         return ch;
  261.     }
  262.  
  263.     if(state==7) {
  264.         ch=(*get)();
  265.         state=5;
  266.         old_state=8;
  267.         return ch;
  268.     }
  269.  
  270.     if(state==8) {
  271.         do ch= (*get)();
  272.         while(ch!='\n');
  273.         state=0;
  274.         return ch;
  275.     }
  276.  
  277.  flushchar:
  278.     ch=(*get)();
  279.     switch(ch) {
  280.     case ' ':
  281.     case '\t':
  282.         do ch=(*get)();
  283.         while(ch!=EOF && IS_WHITESPACE(ch));
  284.         if(ch==EOF)
  285.             return ch;
  286.         if(IS_COMMENT(ch) || (state==0 && IS_LINE_COMMENT(ch)) || ch=='/' || IS_LINE_SEPERATOR(ch)) {
  287.             (*unget)(ch);
  288.             goto flushchar;
  289.         }
  290.         (*unget)(ch);
  291.         if(state==0 || state==2) {
  292.             state++;
  293.             return ' ';
  294.         } else goto flushchar;
  295.  
  296.     case '/':
  297.         ch=(*get)();
  298.         if(ch=='*') {
  299.             for(;;) {
  300.                 do {
  301.                     ch=(*get)();
  302.                     if(ch=='\n')
  303.                         add_newlines++;
  304.                 } while(ch!=EOF && ch!='*');
  305.                 ch=(*get)();
  306.                 if(ch==EOF || ch=='/')
  307.                     break;
  308.                 (*unget)(ch);
  309.             }
  310.             if(ch==EOF)
  311.                 as_warn("End of file in '/' '*' string: */ inserted");
  312.  
  313.             (*unget)(' ');
  314.             goto flushchar;
  315.         } else {
  316. #if defined(I860) || defined(M88K) || defined(M98K) || defined(I386) || \
  317.     defined(HPPA) || defined (SPARC)
  318.           if (ch == '/') {
  319.             do {
  320.               ch=(*get)();
  321.             } while (ch != EOF && (ch != '\n'));
  322.             if (ch == EOF)
  323.               as_warn("End of file before newline in // comment");
  324.             if ( ch == '\n' )    /* Push NL back so we can complete state */
  325.                 (*unget)(ch);
  326.             goto flushchar;
  327.           }
  328. #endif
  329.             if(IS_COMMENT('/') || (state==0 && IS_LINE_COMMENT('/'))) {
  330.                 (*unget)(ch);
  331.                 ch='/';
  332.                 goto deal_misc;
  333.             }
  334.             if(ch!=EOF)
  335.                 (*unget)(ch);
  336.             return '/';
  337.         }
  338.         break;
  339.  
  340.     case '"':
  341.         old_state=state;
  342.         state=5;
  343.         return '"';
  344.         break;
  345.  
  346.     case '\'':
  347.         ch=(*get)();
  348.         if(ch==EOF) {
  349.             as_warn("End-of-file after a ': \\000 inserted");
  350.             ch=0;
  351.         }
  352.         sprintf(out_buf,"(%d)",ch&0xff);
  353.         old_state=state;
  354.         state= -1;
  355.         out_string=out_buf;
  356.         return *out_string++;
  357.  
  358.     case ':':
  359.         if(state!=3)
  360.             state=0;
  361.         return ch;
  362.  
  363.     case '\n':
  364.         if(add_newlines) {
  365.             --add_newlines;
  366.             (*unget)(ch);
  367.         }
  368.     /* Fall through.  */
  369. #if defined(M88K) || defined(M98K) || defined(HPPA)
  370.     case '@':
  371. #else
  372.     case ';':
  373. #endif
  374.         state=0;
  375.         return ch;
  376.  
  377.     default:
  378.     deal_misc:
  379.         if(state==0 && IS_LINE_COMMENT(ch)) {
  380.             do ch=(*get)();
  381.             while(ch!=EOF && IS_WHITESPACE(ch));
  382.             if(ch==EOF) {
  383.                 as_warn("EOF in comment:  Newline inserted");
  384.                 return '\n';
  385.             }
  386.             if(ch<'0' || ch>'9') {
  387.                 do ch=(*get)();
  388.                 while(ch!=EOF && ch!='\n');
  389.                 if(ch==EOF)
  390.                     as_warn("EOF in Comment: Newline inserted");
  391.                 state=0;
  392.                 return '\n';
  393.             }
  394.             (*unget)(ch);
  395.             old_state=4;
  396.             state= -1;
  397.             out_string=".line ";
  398.             return *out_string++;
  399.  
  400.         } else if(IS_COMMENT(ch)) {
  401.             do ch=(*get)();
  402.             while(ch!=EOF && ch!='\n');
  403.             if(ch==EOF)
  404.                 as_warn("EOF in comment:  Newline inserted");
  405.             state=0;
  406.             return '\n';
  407.  
  408.         } else if(state==0) {
  409.             state=2;
  410.             return ch;
  411.         } else if(state==1) {
  412.             state=2;
  413.             return ch;
  414.         } else {
  415.             return ch;
  416.  
  417.         }
  418.     case EOF:
  419.         if(state==0)
  420.             return ch;
  421.         as_warn("End-of-File not at end of a line");
  422.     }
  423.     return -1;
  424. }
  425.  
  426. #ifdef NeXT    /* .include feature */
  427. void
  428. save_scrub_context(
  429. scrub_context_data *save_buffer_ptr)
  430. {
  431.     save_buffer_ptr->last_scrub_file = scrub_file;
  432.     save_buffer_ptr->last_state = state;
  433.     save_buffer_ptr->last_old_state = old_state;
  434.     save_buffer_ptr->last_out_string = out_string;
  435.     memcpy(save_buffer_ptr->last_out_buf, out_buf, sizeof(out_buf));
  436.     save_buffer_ptr->last_add_newlines = add_newlines;
  437.  
  438.     state = 0;
  439.     old_state = 0;
  440.     out_string = NULL;
  441.     memset(out_buf, '\0', sizeof(out_buf));
  442.     add_newlines = 0;
  443. }
  444.  
  445. void
  446. restore_scrub_context(
  447. scrub_context_data *save_buffer_ptr)
  448. {
  449.     scrub_file = save_buffer_ptr->last_scrub_file;
  450.     state = save_buffer_ptr->last_state;
  451.     old_state = save_buffer_ptr->last_old_state;
  452.     out_string = save_buffer_ptr->last_out_string;
  453.     memcpy(out_buf, save_buffer_ptr->last_out_buf, sizeof(out_buf));
  454.     add_newlines = save_buffer_ptr->last_add_newlines;
  455. }
  456. #endif /* NeXT .include feature */
  457.  
  458. #ifdef TEST
  459.  
  460. const char md_comment_chars[] = "|";
  461. const char md_line_comment_chars[] = "#";
  462.  
  463. int
  464. get(
  465. void)
  466. {
  467.     return(getc(stdin));
  468. }
  469.  
  470. void
  471. unget(
  472. int ch)
  473. {
  474.     ungetc(ch, stdin);
  475. }
  476.  
  477. void
  478. main(
  479. int argc,
  480. char *argv[],
  481. char *envp[])
  482. {
  483.     int ch;
  484.  
  485.     while((ch = do_scrub_next_char(get, unget)) != EOF)
  486.         putc(ch, stdout);
  487. }
  488.  
  489. void
  490. as_warn(
  491. const char *format,
  492. ...)
  493. {
  494.     va_list ap;
  495.  
  496.     va_start(ap, format);
  497.     vfprintf(stderr, format, ap);
  498.     fprintf(stderr, "\n");
  499.     va_end(ap);
  500. }
  501. #endif /* TEST */
  502.